package org.jeecg.modules.sggg.controller;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginMember;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.modules.sggg.entity.AppletsLoginModel;
import org.jeecg.modules.sggg.entity.SgMember;
import org.jeecg.modules.sggg.service.ISgMemberService;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/sggg")
@Api(tags = "用户登录")
public class SgLoginController {

    private final ISgMemberService memberService;

    private final RedisUtil redisUtil;

    /**
     * lx --- 2022年11月7日 小程序登录
     *
     * @param model 登录对象
     * @return 结果
     */
    @ApiOperation("小程序登录接口")
    @PostMapping("/login")
    public Result<Object> login(@RequestBody AppletsLoginModel model) {
        if (Strings.isBlank(model.getPhone())) {
            return Result.error("登录失败，phone为null!");
        }
        SgMember member = memberService.queryByPhone(model.getPhone());
        if (member != null) { // 登录

            if (member.getDelFlag() == 1) {
                Result.error("您已被删除，无法登录！");
            }

            if (Strings.isNotBlank(model.getOpenId())) {// 这种情况是之前用小程序登录过的用户

                if (model.getOpenId().equals(member.getOpenId()) || model.getOpenId() != "微信用户") {
                    if (member.getOpenId() == null) {
                        member.setOpenId(model.getOpenId());
                    }
                    JSONObject object = new JSONObject();
                    object.set("m", member);
                    object.set("token", getToken(member));
                    return Result.OK("登录成功！", object);
                } else { // 这种是身份信息不匹配的情况（极少用到）
                    return Result.error(9001, "身份信息不匹配，请输入身份证号核实身份！");
                }
            } else { // 这种是openId为空的情况，数据可能来源于后台手动添加
                return Result.error(9001, "身份信息不匹配，请输入身份证号核实身份！");
            }
        } else { // 注册
            SgMember m = new SgMember();
            m.setPhone(model.getPhone());
            m.setOpenId(model.getOpenId());
            m.setStatus(1);
            m.setSource(1);
            m.setSysOrgCode("A01A01");
            m.setName("微信用户");
            m.setNickName("微信用户");
            m.setAvatar(SymbolConstant.OBS_PATH + "default/avatar.png");
            // 设置预警值
            m.setSbpvalMin(90.0);
            m.setSbpvalMax(140.0);

            m.setDbpvalMin(60.0);
            m.setDbpvalMax(90.0);

            m.setBodyfatMin(6.0);
            m.setBodyfatMax(14.0);

            m.setSugarMin(1.1);
            m.setSugarMax(6.1);

            m.setBloodMin(0.0);
            m.setBloodMax(5.18);

            memberService.save(m);

            JSONObject object = new JSONObject();
            object.set("m", m);
            object.set("token", getToken(m));
            return Result.OK("登录成功，请前往完善信息！", object);
        }
    }

    /**
     * lx ---- 2022年11月7日 核实身份信息
     *
     * @param model 登录对象
     * @return 结果
     */
    @ApiOperation("小程序登录，身份核实")
    @PostMapping("/verify")
    public Result<Object> verify(@RequestBody AppletsLoginModel model) {

        if (Strings.isBlank(model.getOpenId()) || Strings.isBlank(model.getPhone()) || Strings.isBlank(model.getIdCard())) {
            return Result.error("身份信息不完整，请从新输入");
        } else {
            SgMember member = memberService.queryByPhone(model.getPhone());
            /*
             * 通过login的筛选，进来这里的用户只有两种情况
             * 1.获取的openId与数据库存的不一致（极少）
             * 2.后台添加用户后，用户第一次使用小程序登录
             * 这两种情况的最终都是要去更新用户的openId的
             */
            if (member.getIdCard().equals(model.getIdCard())) {
                member.setOpenId(model.getOpenId());
                memberService.updateById(member);
                // 再次进行登录
                return login(model);
            } else {
                return Result.error(9001, "身份不匹配，请从新输入");
            }
        }
    }

    @ApiOperation("/小程序登录获取手机号")
    @GetMapping("/getPhone")
    public Result<String> getPhone(String jsCode) {
        HttpResponse response = HttpRequest
                .get(String.format(
                        "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s",
                        CommonConstant.XCX_APP_ID,
                        CommonConstant.XCX_SECRET,
                        jsCode
                )).execute();
        return Result.OK(response.body());
    }

    /**
     * 获取toke
     *
     * @param member 登录用户对象
     * @return token
     */
    public String getToken(SgMember member) {
        // 先删除，避免redis token数据冗余，也避免多端登录
        redisUtil.removeAll(CommonConstant.PREFIX_MEMBER_TOKEN + member.getId());
        // 存token
        String token = CommonConstant.PREFIX_MEMBER_TOKEN + member.getId() + JwtUtil.sign(member.getPhone(), member.getOpenId());
        LoginMember loginMember = new LoginMember();
        loginMember.setId(member.getId());
        loginMember.setName(member.getName());
        loginMember.setIdCard(member.getIdCard());
        loginMember.setOpenId(member.getOpenId());
        loginMember.setPhone(member.getPhone());
        loginMember.setSex(member.getSex());
        loginMember.setSysOrgCode(member.getSysOrgCode());
        loginMember.setAvatar(member.getAvatar());
        // 设置token缓存有效时间
        redisUtil.set(token, loginMember);
        redisUtil.expire(token, JwtUtil.EXPIRE_TIME * 24 * 7 / 1000);// 存储7天
        // redisUtil.expire(token, 60 * 5);//存储5分钟
        return token;
    }

    /**
     * 修改
     *
     * @param member  居民信息
     * @param request request
     * @return 修改结果
     */
    @PostMapping("/update")
    public Result<Object> update(@RequestBody SgMember member, HttpServletRequest request) {
        if (memberService.updateById(member)) {
            redisUtil.del(request.getHeader(CommonConstant.X_ACCESS_TOKEN));
            JSONObject object = new JSONObject();
            object.set("m", member);
            object.set("token", getToken(member));
            return Result.OK(object);
        }
        return Result.error("修改失败！");
    }

    /**
     * 如果有相同的身份证号，走这个修改接口
     *
     * @param member  居民信息，必须包含要修改的id（updId），本身的id为要删除的id
     * @param request request
     * @return 修改结果
     */
    @PostMapping("/updateForSameIdCard")
    public Result<Object> updateForSameIdCard(@RequestBody SgMember member, HttpServletRequest request) {

        SgMember updateMember = memberService.getById(member.getUpdId());
        updateMember.setPhone(member.getPhone());
        updateMember.setOpenId(member.getOpenId());

        // 这里要物理删除，因为逻辑删除会和唯一索引冲突，所以不要调用mybatis-plus的removeById方法
        memberService.deleteByIds(member.getId());
        if (memberService.updateById(updateMember)) {
            redisUtil.del(request.getHeader(CommonConstant.X_ACCESS_TOKEN));
            JSONObject object = new JSONObject();
            object.set("m", updateMember);
            object.set("token", getToken(updateMember));
            return Result.OK(object);
        }
        return Result.error("修改失败！");
    }

    /**
     * 身份证校验-是否有相同的身份证号
     *
     * @param sgMember 居民表
     * @return 没有返回true，有返回要修改的id
     */
    @PostMapping("/idCardCheck")
    public Result<Boolean> idCardCheck(@RequestBody SgMember sgMember) {
        List<SgMember> isSame = memberService.list(
                new QueryWrapper<SgMember>()
                        .eq("id_card", sgMember.getIdCard())
                        .ne("phone", sgMember.getPhone())
        );

        if (!isSame.isEmpty()) {
            if (isSame.size() > 1) {
                isSame = isSame.stream()
                        .filter(member -> !member.getId().equals(sgMember.getId()))
                        .collect(Collectors.toList());
            }
            return Result.error(isSame.get(0).getId());
        }
        return Result.ok(true);
    }

}
